﻿using System.Diagnostics;
using System.Linq;
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using Core.Shared.Monads;
using Microsoft.Win32;

using Core.Logic;
using Core.Logic.Options;
using UI.Resources.Controls;
using UI.Properties;
using UI.Windows.Dialogs;
using UI.Windows.Wizards;

namespace UI.Windows {
	public partial class MainWindow {
		public MainWindow() {
			InitializeComponent();
		}

		#region Private properties

		public App AppCore {
			get { return (App) Application.Current; }
		}

		#endregion

		#region Commands


		public static readonly RoutedCommand AddResearchCommand = new RoutedCommand("AddResearchCommand", typeof (MainWindow),
			new InputGestureCollection {
				new KeyGesture(Key.A, ModifierKeys.Control)
			});

		public static readonly RoutedCommand RemoveCurrentResearchCommand = new RoutedCommand("RemoveCurrentResearchCommand",
			typeof (MainWindow),
			new InputGestureCollection {
				new KeyGesture(Key.R, ModifierKeys.Control)
			});

		public static readonly RoutedCommand ShowOptionsCommand = new RoutedCommand("ShowOptionsCommand", typeof (MainWindow));

		public static readonly RoutedCommand ShowImportExportOptionsDialogCommand = new RoutedCommand("ShowImportExportOptionsDialogCommand", typeof (MainWindow));

		public static readonly RoutedCommand ResetToDefaultOptionsCommand = new RoutedCommand("ResetToDefaultOptionsCommand", typeof (MainWindow));

		public static readonly RoutedCommand ExportToPdfCommand = new RoutedCommand("ExportToPdfCommand", typeof (MainWindow));

		#endregion

		#region Commands handlers

		private void NewCommandExecuted(object sender, ExecutedRoutedEventArgs e) {
			var newProjectDialog = new NewProjectWizardWindow(AppCore.ModelManager.Models) {
				Owner = this,
				WindowStartupLocation = WindowStartupLocation.CenterOwner
			};

			if ((bool) newProjectDialog.ShowDialog()) {
				AppCore.DependencyContainer.Project = newProjectDialog.NewProject;
				ResearchesListBox.SelectedItem = AppCore.DependencyContainer.Project.CurrentResearch;

				ResearchArea.If(r => r.IsAutoHidden).Do(r => r.ToggleAutoHide());
			}
		}

		private void OpenCommandExecuted(object sender, ExecutedRoutedEventArgs e) {
			var fileDialog = new OpenFileDialog {
				Title = "Choose location...",
				Filter = "All files (*.*)|*.*|Project files (*.raeproj)|*.raeproj",
				FilterIndex = 2
			};

			if ((bool) fileDialog.ShowDialog()) {
				AppCore.DependencyContainer.Project = AppCore.SerializationManager.LoadProject(fileDialog.FileName);
				ResearchesListBox.SelectedItem = AppCore.DependencyContainer.Project.Researches.LastOrDefault();

				ResearchArea.If(r => r.IsAutoHidden).Do(r => r.ToggleAutoHide());
			}
		}

		private void SaveCommandExecuted(object sender, ExecutedRoutedEventArgs e) {
			try {
				AppCore.SerializationManager.SaveProject(AppCore.DependencyContainer.Project, AppCore.DependencyContainer.Project.Path);

				AppCore.DependencyContainer.Project.IsDirty = false;
			}
			catch (UnauthorizedAccessException) {
				string errorLabel = AppCore.LocalizationManager.Localize("RAE:Strings:Warning");
				string errorText = AppCore.LocalizationManager.Localize("RAE:Strings:TEXT_Access_denied");
				MessageBox.Show(errorText, errorLabel, MessageBoxButton.OK, MessageBoxImage.Error);
			}
		}

		private void SaveCommandCanExecuted(object sender, CanExecuteRoutedEventArgs e) {
			e.CanExecute = AppCore.DependencyContainer.Project.Return(p => p.IsDirty, false);
		}

		private void SaveAsCommandExecuted(object sender, ExecutedRoutedEventArgs e) {
			var fileDialog = new SaveFileDialog {
				Title = "Choose location...",
				Filter = "All files (*.*)|*.*|Project files (*.raeproj)|*.raeproj",
				FilterIndex = 2
			};

			if (fileDialog.ShowDialog(this).Value) {
				try {
					AppCore.SerializationManager.SaveProject(AppCore.DependencyContainer.Project, fileDialog.FileName);
					AppCore.DependencyContainer.Project.Path = fileDialog.FileName;

					AppCore.DependencyContainer.Project.IsDirty = false;
				}
				catch (UnauthorizedAccessException) {
					string errorLabel = AppCore.LocalizationManager.Localize("RAE:Strings:Warning");
					string errorText = AppCore.LocalizationManager.Localize("RAE:Strings:TEXT_Access_denied");
					MessageBox.Show(errorText, errorLabel, MessageBoxButton.OK, MessageBoxImage.Error);
				}
			}
		}

		private void CloseCommandExecuted(object sender, ExecutedRoutedEventArgs e) {
			if (!AppCore.DependencyContainer.Project.IsDirty || AppCore.DependencyContainer.Project.IsDirty && TrySafeClosing()) {
				AppCore.DependencyContainer.Project = null;

				ResearchArea.If(r => !r.IsAutoHidden).Do(r => r.ToggleAutoHide());
				InformationArea.If(i => !i.IsAutoHidden).Do(i => i.ToggleAutoHide());
			}
		}

		private void NotNullProjectRequirementCommandCanExecuted(object sender, CanExecuteRoutedEventArgs e) {
			e.CanExecute = AppCore.DependencyContainer.Project.ReturnSuccess();
		}

		private void NotNullResearchRequirementCommandCanExecuted(object sender, CanExecuteRoutedEventArgs e) {
			e.CanExecute = AppCore.DependencyContainer.Project.With(p => p.CurrentResearch).ReturnSuccess();
		}

		private void AddResearchCommandExecuted(object sender, ExecutedRoutedEventArgs e) {
			using (var newResearchWizardWindow = new NewResearchWizardWindow(AppCore.ModelManager.Models) {
				Owner = this,
				WindowStartupLocation = WindowStartupLocation.CenterOwner
			}) {
				if ((bool) newResearchWizardWindow.ShowDialog()) {
					AppCore.DependencyContainer.Project.Researches.Add(newResearchWizardWindow.NewResearch);
					ResearchesListBox.SelectedItem = AppCore.DependencyContainer.Project.Researches.LastOrDefault();

					AppCore.DependencyContainer.Project.IsDirty = true;
				}
			}
		}

		private void RemoveResearchCommandExecuted(object sender, ExecutedRoutedEventArgs e) {
			string errorLabel = AppCore.LocalizationManager.Localize("RAE:Strings:Warning");
			string errorText = AppCore.LocalizationManager.Localize("RAE:Strings:TEXT_Remove_research");
			new WarningMessageBox(errorLabel, errorText).Show(() => {
				AppCore.DependencyContainer.Project.Researches.Remove(AppCore.DependencyContainer.Project.CurrentResearch);
				ResearchesListBox.SelectedItem = AppCore.DependencyContainer.Project.Researches.LastOrDefault();

				if (AppCore.DependencyContainer.Project.Researches.Count == 0) {
					CasesSubstitutableDataGrid.ResetColumns(true);
				}

				AppCore.DependencyContainer.Project.IsDirty = true;
			});
		}

		private void ExportToPdfCommandExecuted(object sender, ExecutedRoutedEventArgs e) {
			Action exportAction = () => {
				var fileDialog = new SaveFileDialog {
					Title = "Choose location...",
					Filter = "All files (*.*)|*.*|PDF files (*.pdf)|*.pdf",
					FilterIndex = 2,
				};
				if ((bool) fileDialog.ShowDialog(this)) {
					AppCore.PdfExportManager.Export(AppCore.DependencyContainer.Project.CurrentResearch, fileDialog.FileName);

					string errorLabel = AppCore.LocalizationManager.Localize("RAE:Strings:Confirmation");
					string errorText = AppCore.LocalizationManager.Localize("RAE:Strings:TEXT_external_viewer");
					new WarningMessageBox(errorLabel, errorText).Show(() => Process.Start(fileDialog.FileName));
				}
			};


			string label = AppCore.LocalizationManager.Localize("RAE:Strings:Warning");
			string text = AppCore.LocalizationManager.Localize("RAE:Strings:TEXT_Export_empty_research");
			if (AppCore.DependencyContainer.Project.CurrentResearch.Cases.Count == 0) {
				new WarningMessageBox(label, text).Show(exportAction);
			}
			else {
				exportAction();
			}
		}

		private void ShowOptionsCommandExecuted(object sender, ExecutedRoutedEventArgs e) {
			var newOptionsDialog = new OptionsWindow(AppCore.OptionsManager.GetOptions()) {
				Owner = this,
				WindowStartupLocation = WindowStartupLocation.CenterOwner
			};

			if ((bool) newOptionsDialog.ShowDialog()) {
				if (newOptionsDialog.Options.IsModified) {
					string optionsPath = String.Format(@"{0}{1}", AppDomain.CurrentDomain.BaseDirectory,
						Settings.Default.OptionsFilePath);

					AppCore.OptionsManager.UpdateOptions(newOptionsDialog.Options);
					AppCore.OptionsManager.SaveOptions(optionsPath);
				}
			}
		}

		private void ShowImportExportOptionsDialogCommandExecuted(object sender, ExecutedRoutedEventArgs e) {
			var importExportDialogWindow = new ImportExportDialogWindow(AppCore.OptionsManager, AppCore.LocalizationManager) {
				Owner = this,
				WindowStartupLocation = WindowStartupLocation.CenterOwner
			};

			if ((bool) importExportDialogWindow.ShowDialog()) {
				AppCore.OptionsManager.ForceNotifyOptionsSubscribers();
			}
		}

		private void ResetToDefaultOptionsCommandExecuted(object sender, ExecutedRoutedEventArgs e) {
			string errorLabel = AppCore.LocalizationManager.Localize("RAE:Strings:Warning");
			string errorText = AppCore.LocalizationManager.Localize("RAE:Strings:TEXT_Reset_to_defaults");
			new WarningMessageBox(errorLabel, errorText).Show(() => {
				string optionsPath = String.Format(@"{0}{1}", AppDomain.CurrentDomain.BaseDirectory,
					Settings.Default.OptionsFilePath);

				AppCore.OptionsManager.UpdateOptions(Options.CreateDefaultOptions(AppCore.LocalizationManager));
				AppCore.OptionsManager.SaveOptions(optionsPath);
			});
		}

		private void ResetToDefaultOptionsCommandCanExecuted(object sender, CanExecuteRoutedEventArgs e) {
			e.CanExecute = AppCore.OptionsManager.GetOptions().IsModified;
		}

		#endregion

		#region Private methods

		private bool TrySafeClosing() {
			string errorLabel = AppCore.LocalizationManager.Localize("RAE:Strings:Warning");
			string errorText = AppCore.LocalizationManager.Localize("RAE:Strings:TEXT_Save_project");
			switch (MessageBox.Show(errorText, errorLabel, MessageBoxButton.YesNoCancel, MessageBoxImage.Warning)) {
				case MessageBoxResult.Yes:
					ApplicationCommands.Save.Execute(null, null);
					break;
				case MessageBoxResult.Cancel:
					return false;
			}

			return true;
		}

		#endregion

		#region Event handlers

		private void ThisWindowLoaded(object sender, RoutedEventArgs e) {
			AppCore.OptionsManager.OptionsChanged += OptionsManagerOptionsChanged;
			AppCore.OptionsManager.ForceNotifyOptionsSubscribers();

			AppCore.DependencyContainer.Project.With(p => p.Researches)
				.If(r => r.Any())
				.Do(r => ResearchesListBox.SelectedItem = AppCore.DependencyContainer.Project.Researches.LastOrDefault());
		}

		private void WindowClosing(object sender, CancelEventArgs e) {
			e.Cancel = AppCore.DependencyContainer.Project.Return(p => p.IsDirty, false) && !TrySafeClosing();
		}

		private void OptionsManagerOptionsChanged(object sender, OptionsManager.OptionsChangedEventArgs e) {
			CasesSubstitutableDataGrid.SetKeywords(e.NewOptions.Keywords);
			CasesSubstitutableDataGrid.SetIdAutogeneration(e.NewOptions.IdAutogeneration);

			if (e.OldOptions != null && e.NewOptions.IdAutogeneration != e.OldOptions.IdAutogeneration) {
				CasesSubstitutableDataGrid.ResetColumns(false);
			}

			AppCore.PdfExportManager.SetFont(e.NewOptions.Font);
		}

		#endregion
	}
}